<?php
/*
  [EWEISHOP] Copyright(C) 2017 Elinkint Inc.
  This is NOT a freeware, use is subject to license terms
   
  WechatApi.php 2018-05-24 18:13 cunx $
   
*/

namespace common\library\wechat;

use common\component\wechat\Wechat;
use common\helpers\Error;
use common\library\wechat\openplatform\OpenPlatform;
use common\models\CoreSettings;
use common\models\pay\ShopPayment;
use common\models\ShopSettings;

class WechatApi
{
    /**
     * 实例集合
     * @var
     * @author cunx
     */
    private static $_instance = [];

    /**
     * 默认实例
     * @var string
     * @author cunx
     */
    public static $apiType = 'officialAccount';

    /**
     * 开放平台设置
     * @var array
     * @author cunx
     */
    private static $openPlatform = [];

    /**
     * 配置
     * @var array
     * @author cunx
     */
    public static $config;

    /**
     * 是否必须使用开放平台
     * 有些接口只允许第三方平台调用
     * @var bool
     * @author cunx
     */
    public static $forceOpenPlatform = false;

    /**
     * 获取实例
     *
     * @return \EasyWeChat\OfficialAccount\Application|\EasyWeChat\Payment\Application|\EasyWeChat\MiniProgram\Application|\EasyWeChat\OpenPlatform\Application|\EasyWeChat\BasicService\Application|\EasyWeChat\Work\Application|\EasyWeChat\MiniProgram\DataCube\Client|\EasyWeChat\Payment\Reverse\Client|\EasyWeChat\OpenPlatform\Authorizer\MiniProgram\Application
     * @author cunx
     */
    public static function getInstance($apiType = null)
    {
        // api 类型标识
        $type = !empty($apiType) ? $apiType : static::$apiType;

        // 是否已存在当前类型的api实例
        if (!self::$_instance[$type]) {
            if (empty(self::$config[$type])) {

                // 未配置参数时，自动加载店铺配置
                self::autoLoadConfig($type);
                if (empty(self::$config[$type])) {
                    // 返回对象化异常
                    $errors = [
                        'officialAccount' => 40400,
                        'payment' => 40401,
                        'miniProgram' => 40402,
                        'openPlatform' => 40403,
                    ];
                    return new Error($errors[$type]);
                }
            }
            // 创建实例
            try {
                $wechat = new Wechat();

                if (self::$config['openPlatform'] || static::$forceOpenPlatform) {
                    $config = CoreSettings::get('wechat_open_platform');
                    if (!empty($config)) {
                        self::$_instance['openPlatform'] = $wechat->getApi('openPlatform', $config);
                        if ($type === 'openPlatform' && self::$_instance['openPlatform']) {
                            return self::$_instance['openPlatform'];
                        }
                        // 获取 refreshToken
                        $refreshToken = OpenPlatform::getRefreshToken(self::$config[$type]['app_id']);
                        if (!is_error($refreshToken)) {
                            self::$_instance[$type] = self::$_instance['openPlatform']->$type(self::$config[$type]['app_id'], $refreshToken);
                        } else {
                            return new Error($refreshToken['error'], $refreshToken['message']);
                        }
                    } else {
                        return new Error(40403);
                    }
                } else {
                    self::$_instance[$type] = $wechat->getApi($type, self::$config[$type]);
                }
            } catch (\Exception $exception) {
                return new Error($exception->getCode(), $exception->getMessage());
            }
        }
        return self::$_instance[$type];
    }

    /**
     * 重新设置配置
     * @param $config
     * @author cunx
     */
    public static function setConfig(string $type, $config)
    {
        if (is_numeric($config)) {
            self::autoLoadConfig($type);
            return;
        }
        self::$config[$type] = $config;
        self::$_instance[$type] = null;
    }

    /**
     * 配置项映射关系
     * @var array
     * @author cunx
     */
    private static $settingConfigKeyRelation = [
        'officialAccount' => 'official_account_config',
        'payment' => 'payment_config',
        'miniProgram' => 'mini_program_config',
        'openPlatform' => 'wechat_open_platform',
    ];

    /**
     * 支付方式 ID
     * @var int
     */
    public static $paymentId = 0;

    /**
     * 自动加载店铺配置
     * @param $type
     * @author cunx
     */
    private static function autoLoadConfig(string $type)
    {
        if ($type === 'openPlatform') {
            $config = CoreSettings::get(self::$settingConfigKeyRelation[$type]);
        } elseif ($type === 'payment') {
            if (is_array(static::$paymentId)) {
                $data = static::$paymentId;
            } else {
                $data = ShopPayment::getPayConfigById(static::$paymentId);
            }

            $config = [];
            $config['app_id'] = $data['appid'];
            $config['mch_id'] = $data['mch_id'];
            $config['key'] = $data['key'];
            if ($data['sub_mch_id']) {
                $config['sub_mch_id'] = $data['sub_mch_id'];
                $config['sub_appid'] = $data['sub_appid'];
            }
            $config['cert_path'] = $data['cert'];
            $config['key_path'] = $data['key_cert'];
        } elseif ($type === 'miniProgram'){
            $config = ShopSettings::get(self::$settingConfigKeyRelation[$type]);
        } elseif ($type === 'officialAccount'){
            $config = \user\apps\wechat\models\Wechat::getWechat();
            if (!empty($config)) {
                $config['secret'] = $config['app_secret'];
                $config['aes_key'] = $config['encoding_aes_key'];
            }
            // $config = ShopSettings::get(self::$settingConfigKeyRelation[$type]);
        }
        self::$config[$type] = $config;
    }

    /**
     * @param string $apiType
     * @param bool $refresh
     * @return array|bool|void
     * @throws \Psr\SimpleCache\InvalidArgumentException
     */
    public static function getAccessToken(string $apiType = '', bool $refresh = false)
    {
        if (empty($apiType) && static::$apiType) {
            $apiType = static::$apiType;
        }
        try {
            $token = self::getInstance($apiType)->access_token->getToken($refresh);
        } catch (\Exception $token) {
        }
        return Wechat::apiError($token);
    }

    /**
     * 设置AccessToken
     * @param string $apiType
     * @param string $token
     * @param int $lifetime
     * @return bool
     */
    public static function setAccessToken(string $apiType = '', string $token, int $lifetime = 7200)
    {
        if (empty($apiType) && static::$apiType) {
            $apiType = static::$apiType;
        }
        try {
            self::getInstance($apiType)->access_token->setToken($token, $lifetime);
        } catch (\Psr\SimpleCache\InvalidArgumentException $exception) {
            return false;
        }
        return true;
    }
}